"""
Case Type   : keep_sync_window
Case Name   : 1主2备环境下，1主1同步1异步，同步时间窗内，同步备注入网络故障
Create At   : 2022/03/08
Owner       : 5321996
Description :
        1.设置以下guc参数
        1.1设置synchronous_standby_names为'dn_6002'
        1.2设置synchronous_commit=on
        1.3设置most_available_sync=on
        1.4设置keep_sync_window=100
        2.建表
        3.模拟同步备网络故障
        4.主节点插入数据
        5.待网卡恢复，查看数据是否同步
        6.清理环境
Expect      :
        1.设置成功
        2.建表成功
        3.成功
        4.阻塞，故障小于时间窗，故障恢复后提交事务成功
        5.同步成功
        6.清理环境完成
History     :
    modified by zwx5321996,2022.03.16，修改断言信息为小写
    modified by lwx1133724 at 2023.12.8:修改故障为网络故障
"""
import os
import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro

pri_sh = CommonSH('PrimaryDbUser')


@unittest.skipIf(3 != pri_sh.get_node_num(), '非1+2环境不执行')
class GucParameters(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.constant = Constant()
        self.com = Common()
        self.standby_sh1 = CommonSH('Standby1DbUser')
        self.standby_sh2 = CommonSH('Standby2DbUser')
        self.db_primary_user_node = Node(node='PrimaryDbUser')
        self.sta1_root = Node(node='Standby1Root')
        self.pri_root_node = Node(node='PrimaryRoot')
        self.log.info('---获取参数默认值--')
        cmd1 = pri_sh.executDbSql('show keep_sync_window;')
        self.log.info(cmd1)
        self.default_value1 = cmd1.splitlines()[2].strip()
        cmd2 = pri_sh.executDbSql('show synchronous_standby_names;')
        self.log.info(cmd2)
        self.default_value2 = cmd2.splitlines()[2].strip()
        cmd3 = pri_sh.executDbSql('show synchronous_commit;')
        self.log.info(cmd3)
        self.default_value3 = cmd3.splitlines()[2].strip()
        cmd4 = pri_sh.executDbSql('show most_available_sync;')
        self.log.info(cmd4)
        self.default_value4 = cmd4.splitlines()[2].strip()
        self.log.info('---获取主节点nodename--')
        self.pri_node_name = self.pri_root_node.sh("uname -n").result()
        self.log.info(self.pri_node_name)
        self.tb_name = "tb_keep_sync_window_0001"

    def test_keep_sync_window(self):
        text = '--step1:设置guc参数;expect:设置成功--'
        self.log.info(text)
        self.log.info('设置synchronous_standby_names=dn_6002')
        result = pri_sh.executeGsguc("reload",
                                     self.constant.GSGUC_SUCCESS_MSG,
                                     f"synchronous_standby_names="
                                     f"'{macro.DN_NODE_NAME.split('/')[1]}'",
                                     node_name=f'{self.pri_node_name}')

        self.assertTrue(result, '执行失败' + text)
        self.log.info('设置synchronous_commit=on')
        result = pri_sh.executeGsguc("reload",
                                     self.constant.GSGUC_SUCCESS_MSG,
                                     f"synchronous_commit=on")

        self.assertTrue(result, '执行失败' + text)
        self.log.info('设置most_available_sync=on')
        result = pri_sh.executeGsguc("reload",
                                     self.constant.GSGUC_SUCCESS_MSG,
                                     f"most_available_sync=on")

        self.assertTrue(result, '执行失败' + text)
        self.log.info('设置keep_sync_window=100')
        result = pri_sh.executeGsguc("reload",
                                     self.constant.GSGUC_SUCCESS_MSG,
                                     f"keep_sync_window=100")

        self.assertTrue(result, '执行失败' + text)
        pri_sh.stopDbCluster()
        time.sleep(2)
        pri_sh.startDbCluster()

        text = '--step2:建表;expect:建表成功--'
        self.log.info(text)
        sql_cmd = pri_sh.executDbSql(f"drop table if exists "
                                     f"{self.tb_name};"
                                     f"create table {self.tb_name}"
                                     f"(id int,name text);")
        self.log.info(sql_cmd)
        self.assertIn(self.constant.TABLE_CREATE_SUCCESS, sql_cmd,
                      '执行失败' + text)

        text = '--step3:模拟同步备网络故障;expect:成功--'
        self.log.info(text)
        self.log.info('----获取网卡----')
        network_card_cmd = 'ifconfig'
        self.log.info(network_card_cmd)
        network_card_result = self.sta1_root.sh(network_card_cmd).result()
        network_card_list = network_card_result.split('\n\n')
        self.log.info(network_card_list)
        network_card = ''
        for network_card_item in network_card_list:
            if self.sta1_root.db_host in network_card_item:
                network_card = network_card_item.split(':')[0].strip()
                self.log.info(network_card)

        self.log.info('----故障注入----')
        inject_cmd = f'rNet_down (dev, time)values({network_card}, 60)'
        inject_result = self.com.cfe_inject(self.sta1_root, inject_cmd)
        self.log.info(inject_result)
        self.assertIn(self.constant.cfe_inject_netdown_success_msg,
                      inject_result)
        time.sleep(3)

        text = '--step4:主节点插入数据;expect:主节点阻塞--'
        self.log.info(text)
        sql_cmd = f"select timenow();" \
                  f"insert into {self.tb_name} values(generate_series(1,10)," \
                  f"'column_'|| generate_series(1,10));" \
                  f"select timenow();"
        self.log.info(sql_cmd)
        insert_thread = ComThread(pri_sh.executDbSql, args=(sql_cmd,))
        insert_thread.setDaemon(True)
        insert_thread.start()

        self.log.info('获取step4结果，阻塞，故障小于时间窗，故障恢复后提交事务成功')
        insert_thread.join(10 * 600)
        insert_thread_result = insert_thread.get_result()
        self.log.info(insert_thread_result)
        self.assertIn(self.constant.insert_success_msg, insert_thread_result,
                      '执行失败:' + text)

        text = '----step5:待网卡恢复，查看数据是否同步;expect:数据同步完成----'
        self.log.info(text)
        sql_cmd = f"select * from {self.tb_name};"
        msg_primary = pri_sh.executDbSql(sql_cmd)
        self.log.info(msg_primary)
        msg_standby1 = self.standby_sh1.executDbSql(sql_cmd)
        self.log.info(msg_standby1)
        self.assertEqual(msg_primary, msg_standby1, '执行失败:' + text)
        msg_standby2 = self.standby_sh2.executDbSql(sql_cmd)
        self.log.info(msg_standby2)
        self.assertEqual(msg_primary, msg_standby2, '执行失败:' + text)

    def tearDown(self):
        text = '--step6:清理环境;expect:清理环境完成--'
        self.log.info(text)
        self.log.info('删表')
        drop_cmd = pri_sh.executDbSql(f"drop table if exists "
                                      f"{self.tb_name};")
        self.log.info(drop_cmd)
        self.log.info('恢复参数默认值')
        result1 = pri_sh.executeGsguc("reload",
                                      self.constant.GSGUC_SUCCESS_MSG,
                                      f"synchronous_commit="
                                      f"{self.default_value3}")

        result2 = pri_sh.executeGsguc("reload",
                                      self.constant.GSGUC_SUCCESS_MSG,
                                      f"most_available_sync="
                                      f"{self.default_value4}")

        result3 = pri_sh.executeGsguc("reload",
                                      self.constant.GSGUC_SUCCESS_MSG,
                                      f"keep_sync_window="
                                      f"{self.default_value1}")
        result4 = pri_sh.executeGsguc("reload",
                                      self.constant.GSGUC_SUCCESS_MSG,
                                      f"synchronous_standby_names="
                                      f"'{self.default_value2}'",
                                      node_name=f'{self.pri_node_name}')
        result = pri_sh.stopDbCluster()
        self.assertTrue(result, '执行失败' + text)
        result = pri_sh.startDbCluster()
        self.assertTrue(result, '执行失败' + text)
        self.log.info('断言teardown成功')
        self.assertIn(self.constant.TABLE_DROP_SUCCESS, drop_cmd,
                      '执行失败' + text)
        self.assertEqual(True, result1, '执行失败' + text)
        self.assertEqual(True, result2, '执行失败' + text)
        self.assertEqual(True, result3, '执行失败' + text)
        self.assertEqual(True, result4, '执行失败' + text)
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
